package com.wbl.train.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wbl.train.business.service.*;
import com.wbl.train.common.business.dto.DailyTrainDto;
import com.wbl.train.common.business.entity.DailyTrainEntity;
import com.wbl.train.business.mapper.DailyTrainMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wbl.train.common.business.entity.TrainEntity;
import com.wbl.train.common.business.vo.DailyTrainVo;
import com.wbl.train.common.exception.ApplicationException;
import com.wbl.train.common.page.PageVo;
import com.wbl.train.common.result.ResultCode;
import com.wbl.train.common.utils.SnowUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Date;
import java.util.List;

/**
 * 每日车次 服务实现类
 * @author 王博纶
 * @since 2024-02-10
 */
@Slf4j
@AllArgsConstructor
@Service
public class DailyTrainServiceImpl extends ServiceImpl<DailyTrainMapper, DailyTrainEntity> implements DailyTrainService {

    private final TrainService trainService;
    private final DailyTrainStationService dailyTrainStationService;
    private final DailyTrainCarriageService dailyTrainCarriageService;
    private final DailyTrainSeatService dailyTrainSeatService;
    private final DailyTrainTicketService dailyTrainTicketService;
    private final DailySkTokenService dailySkTokenService;

    @Override
    public PageVo<DailyTrainEntity> queryDailyTrain(DailyTrainDto dailyTrainDto) {
        // 获取分页所需要的参数
        int page = dailyTrainDto.getPage();
        int limit = dailyTrainDto.getLimit();

        LambdaQueryWrapper<DailyTrainEntity> dailyTrainWrapper = new LambdaQueryWrapper<DailyTrainEntity>()
                // 火车车次编号查询
                .eq(ObjectUtil.isNotEmpty(dailyTrainDto.getCode()),DailyTrainEntity::getCode,dailyTrainDto.getCode())
                // 根据日期查询
                .eq(ObjectUtil.isNotNull(dailyTrainDto.getDate()),DailyTrainEntity::getDate,dailyTrainDto.getDate())
                .orderByDesc(DailyTrainEntity::getDate)
                .orderByAsc(DailyTrainEntity::getCode);
        //创建分页对象
        IPage<DailyTrainEntity> dailyTrainPage = new Page<>(page,limit);
        //调用分页方法
        IPage<DailyTrainEntity> dailyTrainPageData = page(dailyTrainPage,dailyTrainWrapper);
        // 获取查询出来的数据集合
        List<DailyTrainEntity> records = dailyTrainPageData.getRecords();
        // 将数据塞到PageVo类中并返回出去
        return new PageVo<DailyTrainEntity>()
                .setDataList(records)
                .setPageSize(limit).setCurrentPage(page)
                .setTotal((int) dailyTrainPageData.getTotal())
                .setPages((int) dailyTrainPageData.getPages());
    }

    @Override
    public boolean insertAndUpdateTrain(DailyTrainEntity dailyTrain) {
        // 获取当前的时间 --- 用于创建和修改的时候的时间填充
        DateTime now = DateTime.now();
        // 设置火车车次的修改时间
        dailyTrain.setUpdateTime(now);
        // 判断Id是否为空
        if(ObjectUtil.isNotNull(dailyTrain.getId())){
            // 根据id查询车站信息
            DailyTrainEntity dailyTrainEntity = this.getById(dailyTrain.getId());
            // 当前id对应的无火车车次信息
            if(ObjectUtil.isNull(dailyTrainEntity)){
                throw new ApplicationException(ResultCode.DATA_NOT_EXIST,"当前火车车次不存在");
            }
            // 更新火车车次信息
            return this.updateById(dailyTrain);
        }
        // 保存之前的唯一键校验
        DailyTrainEntity dailyTrainEntity = getTrainByUniqueKey(dailyTrain.getCode(),dailyTrain.getDate());
        // 查询出的trainEntity不为空，不允许新增
        if(ObjectUtil.isNotEmpty(dailyTrainEntity)){
            throw new ApplicationException(ResultCode.DATA_EXIST,"当前火车车次已存在");
        }
        // 给新增的火车车次设置Id，创建时间和修改时间
        dailyTrain.setId(SnowUtil.getSnowflakeNextId())
                .setCreateTime(now);
        // 新增火车车次
        return this.save(dailyTrain);
    }

    /**
     * 根据唯一键查询 train 火车信息
     * @param code 火车车次编码
     * @param date 火车车次当日日期
     * @return train 火车信息
     */
    private DailyTrainEntity getTrainByUniqueKey(String code, LocalDate date) {
        // 通过code进行车站信息的查询
        LambdaQueryWrapper<DailyTrainEntity> wrapper = new LambdaQueryWrapper<DailyTrainEntity>()
                .eq(DailyTrainEntity::getCode, code)
                .eq(DailyTrainEntity::getDate,date)
                ;
        return this.getOne(wrapper);
    }

    @Override
    public List<DailyTrainVo> queryAllDailyTrain() {
        LambdaQueryWrapper<DailyTrainEntity> trainWrapper = new LambdaQueryWrapper<DailyTrainEntity>()
                // 设置排序 --- 按照code字段进行排序
                .orderByAsc(DailyTrainEntity::getCode);
        List<DailyTrainEntity> dailyTrainList = this.list(trainWrapper);
        return BeanUtil.copyToList(dailyTrainList, DailyTrainVo.class);
    }

    @Override
    @Transactional
    public void genDaily(LocalDate date) {
        Date now = new Date();
        // 查询所有的基础车次信息
        List<TrainEntity> trains = trainService.selectAll();
        if(CollUtil.isEmpty(trains)){
            log.error("没有车次基础数据，任务结束");
            throw new ApplicationException(ResultCode.DATA_NOT_EXIST,"没有车次基础数据，任务结束");
        }
        // 根据基本车次信息生成每日车次
        for (TrainEntity train : trains) {
            genDailyTrain(date, train,now);
        }
    }

    /**
     * 生成每日车次信息
     * @param date 要生成的日期
     * @param train 要生成的车次信息
     * @param now 修改时间和创建时间的当前时间
     */
    @Transactional
    public void genDailyTrain(LocalDate date, TrainEntity train, Date now) {
        log.info("生成日期【{}】车次【{}】的车次信息开始",date,train.getCode());
        LambdaQueryWrapper<DailyTrainEntity> wrapper = new LambdaQueryWrapper<DailyTrainEntity>()
                .eq(DailyTrainEntity::getCode, train.getCode())
                .eq(DailyTrainEntity::getDate, date)
                ;
        DailyTrainEntity dailyTrainEntity = this.getOne(wrapper);
        if(ObjectUtil.isNotEmpty(dailyTrainEntity)){
            // 删除该车次信息
            this.removeById(dailyTrainEntity.getId());
        }
        // 生成每日车次
        this.save(BeanUtil.copyProperties(train, DailyTrainEntity.class)
                .setId(SnowUtil.getSnowflakeNextId())
                .setDate(date)
                .setCreateTime(now)
                .setUpdateTime(now));
        // 保存完在查询一次 --- 防止下面调用的时候发生空指针异常
        dailyTrainEntity = this.getOne(wrapper);

        // 生成每日车次的车站信息
        dailyTrainStationService.genDailyStation(date,train.getCode(),now);
        // 生成每日车次的车厢信息
        dailyTrainCarriageService.genDailyCarriage(date,train.getCode(),now);
        // 生成每日车次的座位信息
        dailyTrainSeatService.genDailySeat(date,train.getCode(),now);
        // 生成每日余票信息
        dailyTrainTicketService.genTrainTicket(dailyTrainEntity,date,train.getCode(),now);
        log.info("生成日期【{}】车次【{}】的车次信息结束",date,train.getCode());
        // 生成每日令牌余票信息
        dailySkTokenService.genDaily(date, train.getCode());
        log.info("生成日期【{}】车次【{}】的令牌余票信息结束",date,train.getCode());
    }
}
